using System;
using System.ComponentModel;
using System.Net.NetworkInformation;
using System.Threading;
using RollManager.Library.ActionSteps.BaseClasses;
using RollManager.Library.Utils;

namespace RollManager.Library.ActionSteps
{
    [Serializable]
    public class PingStep : ActionStep
    {
        public PingCondition m_condition = PingCondition.None;
        public int m_numTries = 0;

        [DisplayName("Wait Condition")]
        [Description("The condition of the ping on which this step should wait.  Set it to none to not wait.")]
        public PingCondition WaitCondition
        {
            get
            {
                return m_condition;
            }
            set
            {
                m_condition = value;
            }
        }

        [DisplayName( "Maximum Tries" )]
        [Description( "The maximum number of times to ping the server and look for a condition.  Set it to 0 to have it try indefinitely." )]
        public int NumTries
        {
            get
            {
                return m_numTries;
            }
            set
            {
                m_numTries = value;
            }
        }

        public override string Name
        {
            get { return "Ping Computer"; }
        }

        protected override void Run()
        {
            if( m_condition == PingCondition.None )
            {
                // Just ping once because there is no condition.
                doPing();
            }
            else if( m_numTries == 0 )
            {
                // Ping until the condition is met there is no max tries.
                while( m_condition != doPing() )
                {
                    if( m_condition == PingCondition.Failed )
                    {
                        Thread.Sleep( 1000 );
                    }
                }
            }
            else
            {
                // Ping until condition is met up to max tries.
                for( int i = 0 ; i < m_numTries ; i++ )
                {
                    if( m_condition == doPing() )
                    {
                        break;
                    }
                    if( m_condition == PingCondition.Failed )
                    {
                        Thread.Sleep( 1000 );
                    }
                }
            }
        }

        protected override void Simulate()
        {
            doPing();
        }

        private PingCondition doPing()
        {
            return doPing( CurrentServer, Progress );
        }

        public static PingCondition doPing( string server, ProgressReporter progress )
        {
            PingReply reply = new Ping().Send( server );
            if( reply.Status == IPStatus.Success )
            {
                progress.AddFormat( "Reply from {0}: bytes={1} time={2}ms TTL={3}",
                    reply.Address, reply.Buffer.Length, reply.RoundtripTime, reply.Options.Ttl );
                return PingCondition.Succeeded;
            }
            else
            {
                progress.AddFormat( "Ping failed: {0}", reply.Status );
                return PingCondition.Failed;
            }
        }
    }
}
